package com.example.teesystem.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.teesystem.common.cache.UserCache;
import com.example.teesystem.common.exception.CustomException;
import com.example.teesystem.common.utils.Response;
import com.example.teesystem.common.utils.ResultCode;
import com.example.teesystem.entity.Class;
import com.example.teesystem.entity.ClassStudent;
import com.example.teesystem.entity.User;
import com.example.teesystem.entity.vo.classStudent.ClassStudentResponseVo;
import com.example.teesystem.entity.vo.classStudent.ClassStudentUpdateVo;
import com.example.teesystem.entity.vo.classStudent.ClassStudentUploadVo;
import com.example.teesystem.entityDto.StudentDto;
import com.example.teesystem.filter.MyHandlerInterceptor;
import com.example.teesystem.mapper.ClassMapper;
import com.example.teesystem.mapper.UserMapper;
import com.example.teesystem.service.ClassService;
import com.example.teesystem.service.ClassStudentService;
import com.example.teesystem.mapper.ClassStudentMapper;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
* @author 28131
* @description 针对表【t_class_student】的数据库操作Service实现
* @createDate 2022-03-30 13:50:39
*/
@Service
@RequiredArgsConstructor
public class ClassStudentServiceImpl extends ServiceImpl<ClassStudentMapper, ClassStudent>
    implements ClassStudentService{
    private final ClassService classService;
    private final ClassStudentMapper classStudentMapper;
    private final UserMapper userMapper;
    private final ClassMapper classMapper;
    
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public Response add(ClassStudentUploadVo classStudentUploadVo) {
        Class myClass = classMapper.getClassById(classStudentUploadVo.getClassId());
        List<Integer> classIds = classMapper.getClassIdsByCourse(myClass.getCourseId());
        List<Integer> studentId = new ArrayList<>();
        List<Integer> errorStudent = new ArrayList<>();
        for (Integer id : classIds) {
            studentId.addAll(classStudentMapper.getStudentIdByClassId(id));
        }
        for (Integer integer : studentId) {
            for (int j = 0; j < classStudentUploadVo.getStudentIds().size(); j++) {
                if (integer.equals(classStudentUploadVo.getStudentIds().get(j))) {
                    errorStudent.add(integer);
                }
            }
        }
        try{
            if(errorStudent.size()!=0){
                Map<String,List<Integer>> map = new HashMap<>();
                map.put("errorStudent",errorStudent);
                return Response.error(ResultCode.CLASS_STUDENT,map);
            }else {
                for(int i = 0; i < classStudentUploadVo.getStudentIds().size();i++){
                    ClassStudent classStudent = new ClassStudent();
                    classStudent.setClassId(classStudentUploadVo.getClassId());
                    classStudent.setStudentId(classStudentUploadVo.getStudentIds().get(i));
                    classStudentMapper.insert(classStudent);
                }
                return Response.ok();
            }
        }catch (Exception e){
            return Response.error(ResultCode.UPDATE_MESSAGE_ERROR);
        }


    }
    
    /**
     *
     * @param studentId
     * @return
     */
    private boolean verifyStudent(int studentId, int classId) {
        QueryWrapper<ClassStudent> wrapper = new QueryWrapper<>();
        wrapper.eq("student_id", studentId);
        List<Integer> classIds = this.list(wrapper).stream()
                .map(ClassStudent::getClassId)
                .collect(Collectors.toList());
        if(classIds.isEmpty()) {
            return false;
        }
        classIds.add(classId);
        List<Integer> courseIds = this.classService.listByIds(classIds).stream().map(Class::getCourseId).collect(Collectors.toList());
        long count = courseIds.stream().distinct().count();
        return classIds.size() != count;
    }
    
    @Override
    public boolean remove(ClassStudentUploadVo classStudentUploadVo) {
        QueryWrapper<ClassStudent> wrapper = new QueryWrapper<>();
        wrapper.eq("class_id", classStudentUploadVo.getClassId())
                .in("student_id", classStudentUploadVo.getStudentIds());
        return this.remove(wrapper);
    }
    
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public boolean update(ClassStudentUpdateVo classStudentUpdateVo) {
        // 首先判断移动前后的班级是否是同一课程下
        QueryWrapper<Class> classWrapper = new QueryWrapper<>();
        classWrapper.in("id", classStudentUpdateVo.getCurClassId(), classStudentUpdateVo.getNextClassId());
        List<Class> classList = classService.list(classWrapper);
        if(classList.size() != 2 || !classList.get(0).getCourseId().equals(classList.get(1).getCourseId())) {
            throw new CustomException(ResultCode.PARAMETER_ERROR);
        }
        
        UpdateWrapper<ClassStudent> wrapper = new UpdateWrapper<>();
        wrapper.eq("class_id", classStudentUpdateVo.getCurClassId())
                .in("student_id", classStudentUpdateVo.getStudentIds())
                .set("class_id", classStudentUpdateVo.getNextClassId());
        return this.update(wrapper);
    }
    
    @Override
    public List<ClassStudentResponseVo> get(Integer classId) {
        QueryWrapper<ClassStudent> wrapper = new QueryWrapper<>();
        wrapper.eq("class_id", classId);
        
        return this.list(wrapper).stream()
                .map(this::convertToResponseVo)
                .collect(Collectors.toList());
    }
    
    @Override
    public List<ClassStudent> getMyClass() {
        QueryWrapper<ClassStudent> wrapper = new QueryWrapper<>();
        wrapper.eq("student_id", MyHandlerInterceptor.getUid());
        return this.list(wrapper);
    }
    
    @Override
    public boolean applyJoin(Integer classId) {
        int studentId = MyHandlerInterceptor.getUid();
        if(this.verifyStudent(studentId, classId)) {
            return false;
        }
        return this.save(ClassStudent.builder().classId(classId).studentId(studentId).build());
    }
    
    private ClassStudentResponseVo convertToResponseVo(ClassStudent classStudent) {
        User user = UserCache.userMap.getOrDefault(classStudent.getStudentId(), UserCache.NONE_USER);
        return new ClassStudentResponseVo(user);
    }


    public int getIdByMessage(Integer classId, Integer studentId){
        try{
            return classStudentMapper.getIdByMessage(studentId, classId);
        }catch (Exception e){
            return -1;
        }
    }

    @Override
    public Response getStudentMessage(Integer classId, Integer studentId) {
        if(getIdByMessage(classId,studentId) == -1){
            return Response.error(ResultCode.PARAMETER_ERROR);
        }
        User u = new User();
        u.setMyName("用户未找到，或已注销");
        return Response.ok(new StudentDto(UserCache.userMap.getOrDefault(studentId,u)));
    }

    @Override
    public Response updateStudentAccountType(Integer classId, Integer studentId, Integer accountType) {
        if(getIdByMessage(classId,studentId) == -1){
            return Response.error(ResultCode.PARAMETER_ERROR);
        }
        User u = UserCache.userMap.get(studentId);
        if(u == null){
            return Response.error(ResultCode.PARAMETER_ERROR);
        }
        if(u.getType()!=2){
            return Response.error(ResultCode.NO_PERMISSION);
        }
        userMapper.updateAccountTypeById(studentId,accountType);
        u.setAccountType(accountType);
        UserCache.updateUser(studentId,u);
        return Response.ok();
    }

    @Override
    public Response updateStudentPassword(Integer classId, Integer studentId, String password) {
        if(getIdByMessage(classId,studentId) == -1){
            return Response.error(ResultCode.PARAMETER_ERROR);
        }
        User u = UserCache.userMap.get(studentId);
        if(u == null){
            return Response.error(ResultCode.PARAMETER_ERROR);
        }
        if(u.getType()!=2){
            return Response.error(ResultCode.NO_PERMISSION);
        }
        userMapper.updatePasswordById(studentId, password);
        u.setPassword(password);
        UserCache.updateUser(studentId,u);
        return Response.ok();
    }
}
